package com.zxg.zbc.web.common.util;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;

import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

public class BaiduLBS {

  private static final String LAT = "lat";
  private static final String LNG = "lng";
  private static final String AK  = "ED70c10562298ca4e510cf265a632859";
  private static final String SK  = "E31ebf63d28cc91fe7119c7b1cc0238d";

  public static void main(String[] args) throws Exception {

    BaiduLBS baidu = new BaiduLBS();

    Map hz = baidu.getLocationByIp("101.69.229.30");
    Map zz = baidu.getLocationByCity("郑州市");

    System.out.println("杭州到郑州距离＝》" + getLineDistance(hz, zz));

    baidu.getDrivingDistance(hz, zz);
  }

  public double getDrivingDistance(Map<String, Double> origin, Map<String, Double> destination) throws Exception {

    String origins = origin.get(LAT) + "," + origin.get(LNG);
    String destinations = destination.get(LAT) + "," + destination.get(LNG);

    // 算得sn后发送get请求
    HttpClient client = new DefaultHttpClient();
    HttpGet httpget = new HttpGet(
        "http://api.map.baidu.com/routematrix/v2/driving?coord_type＝gcj02&destinations=" + destinations + "&origins=" + origins + "&ak=" + AK);
    HttpResponse response = client.execute(httpget);
    InputStream is = response.getEntity().getContent();
    String result = inStream2String(is);
    // 打印响应内容
    System.out.println(result);

    // 获取实际距离
    JSONObject json = JSON.parseObject(result);

    String distance = JSON.parseObject(json.getJSONArray("result").get(0).toString()).getJSONObject("distance").get("value").toString();

    if (StringUtils.isNotEmpty(distance)) {
      double dist = Math.round(Double.parseDouble(distance) / 1000);
      return dist;
    }
    return 0;

  }

  public Map<String, Double> getLocationByIp(String ip) throws Exception {

    Map paramsMap = new LinkedHashMap<String, String>();
    paramsMap.put("ak", AK);
    paramsMap.put("coor", "gcj02");
    paramsMap.put("ip", ip);

    String paramsStr = toQueryString(paramsMap);

    String wholeStr = new String("/location/ip?" + paramsStr + SK);

    // 对上面wholeStr再作utf8编码
    String tempStr = URLEncoder.encode(wholeStr, "UTF-8");

    String sn = MD5(tempStr);
    System.out.println("sn=>" + sn);

    // 算得sn后发送get请求
    HttpClient client = new DefaultHttpClient();
    String url = "http://api.map.baidu.com/location/ip?ak=" + AK + "&coor=gcj02&ip=" + ip + "&sn=" + sn;
    System.out.println("url -> " + url);
    HttpGet httpget = new HttpGet(url);
    HttpResponse response = client.execute(httpget);
    InputStream is = response.getEntity().getContent();
    String result = inStream2String(is);

    // 打印响应内容
    System.out.println(result);

    // 获取经纬度
    JSONObject json = JSON.parseObject(result);

    String longtitude = json.getJSONObject("content").getJSONObject("point").getString("x");
    String latitude = json.getJSONObject("content").getJSONObject("point").getString("y");

    System.out.println("x -> " + latitude + " y -> " + longtitude);
    Map<String, Double> map = new HashMap<String, Double>();

    map.put(LNG, Double.parseDouble(longtitude));
    map.put(LAT, Double.parseDouble(latitude));

    return map;

  }

  public Map<String, Double> getLocationByCity(String city) throws Exception {

    Map paramsMap = new LinkedHashMap<String, String>();
    paramsMap.put("address", city);
    paramsMap.put("output", "json");
    paramsMap.put("ak", AK);

    String paramsStr = toQueryString(paramsMap);
    String wholeStr = new String("/geocoder/v2/?" + paramsStr + SK);

    String tempStr = URLEncoder.encode(wholeStr, "UTF-8");

    String sn = MD5(tempStr);
    System.out.println("sn=>" + sn);

    // 算得sn后发送get请求
    HttpClient client = new DefaultHttpClient();
    String url = "http://api.map.baidu.com/geocoder/v2/?address=" + city + "&output=json&ak=" + AK + "&sn=" + sn;
    HttpGet httpget = new HttpGet(url);
    HttpResponse response = client.execute(httpget);
    InputStream is = response.getEntity().getContent();
    String result = inStream2String(is);
    // 打印响应内容
    System.out.println(result);

    // 获取经纬度
    JSONObject json = JSON.parseObject(result);

    String longtitude = json.getJSONObject("result").getJSONObject("location").getString(LNG);
    String latitude = json.getJSONObject("result").getJSONObject("location").getString(LAT);

    System.out.println("lat -> " + latitude + " lng -> " + longtitude);

    Map<String, Double> map = new HashMap<String, Double>();

    map.put(LNG, Double.parseDouble(longtitude));
    map.put(LAT, Double.parseDouble(latitude));

    return map;
  }

  public static double getLineDistance(Map<String, Double> userLoc, Map<String, Double> sellerLoc) {

    double longitude1 = userLoc.get(LNG);
    double latitude1 = userLoc.get(LAT);
    double longitude2 = sellerLoc.get(LNG);
    double latitude2 = sellerLoc.get(LAT);

    // 维度
    double lat1 = (Math.PI / 180) * latitude1;
    double lat2 = (Math.PI / 180) * latitude2;
    // 经度
    double lon1 = (Math.PI / 180) * longitude1;
    double lon2 = (Math.PI / 180) * longitude2;
    // 地球半径
    double R = 6371;
    // 两点间距离 km，如果想要米的话，结果*1000就可以了
    double d = Math.acos(Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1)) * R;
    return d;
  }

  public void testGet() throws Exception {

    // 计算sn跟参数对出现顺序有关，get请求请使用LinkedHashMap保存<key,value>，该方法根据key的插入顺序排序；post请使用TreeMap保存<key,value>，该方法会自动将key按照字母a-z顺序排序。所以get请求可自定义参数顺序（sn参数必须在最后）发送请求，但是post请求必须按照字母a-z顺序填充body（sn参数必须在最后）。以get请求为例：http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=yourak，paramsMap中先放入address，再放output，然后放ak，放入顺序必须跟get请求中对应参数的出现顺序保持一致。
    Map paramsMap = new LinkedHashMap<String, String>();
    paramsMap.put("address", "百度大厦");
    paramsMap.put("output", "json");
    paramsMap.put("ak", "ED70c10562298ca4e510cf265a632859");

    // 调用下面的toQueryString方法，对LinkedHashMap内所有value作utf8编码，拼接返回结果address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourak
    String paramsStr = toQueryString(paramsMap);

    // 对paramsStr前面拼接上/geocoder/v2/?，后面直接拼接yoursk得到/geocoder/v2/?address=%E7%99%BE%E5%BA%A6%E5%A4%A7%E5%8E%A6&output=json&ak=yourakyoursk
    String wholeStr = new String("/geocoder/v2/?" + paramsStr + "E31ebf63d28cc91fe7119c7b1cc0238d");

    // 对上面wholeStr再作utf8编码
    String tempStr = URLEncoder.encode(wholeStr, "UTF-8");

    // 调用下面的MD5方法得到最后的sn签名7de5a22212ffaa9e326444c75a58f9a0
    String sn = MD5(tempStr);
    System.out.println("sn=>" + sn);

    // 算得sn后发送get请求
    HttpClient client = new DefaultHttpClient();
    HttpGet httpget = new HttpGet("http://api.map.baidu.com/geocoder/v2/?address=百度大厦&output=json&ak=ED70c10562298ca4e510cf265a632859&sn=" + sn);
    HttpResponse response = client.execute(httpget);
    InputStream is = response.getEntity().getContent();
    String result = inStream2String(is);
    // 打印响应内容
    System.out.println(result);
  }

  public void testPost() throws Exception {
    /**
     * 以http://api.map.baidu.com/geodata/v3/geotable/create创建表为例
     */
    LinkedHashMap<String, String> paramsMap = new LinkedHashMap<String, String>();
    paramsMap.put("geotype", "1");
    paramsMap.put("ak", "ED70c10562298ca4e510cf265a632859");
    paramsMap.put("name", "geotable80");
    paramsMap.put("is_published", "1");

    // post请求是按字母序填充，对上面的paramsMap按key的字母序排列
    Map<String, String> treeMap = new TreeMap<String, String>(paramsMap);
    String paramsStr = toQueryString(treeMap);

    String wholeStr = new String("/geodata/v3/geotable/create?" + paramsStr + "E31ebf63d28cc91fe7119c7b1cc0238d");
    String tempStr = URLEncoder.encode(wholeStr, "UTF-8");
    // 调用下面的MD5方法得到sn签名值
    String sn = MD5(tempStr);

    HttpClient client = new DefaultHttpClient();
    HttpPost post = new HttpPost("http://api.map.baidu.com/geodata/v3/geotable/create");
    List<NameValuePair> params = new ArrayList<NameValuePair>();
    params.add(new BasicNameValuePair("geotype", "1"));
    params.add(new BasicNameValuePair("ak", "ED70c10562298ca4e510cf265a632859"));
    params.add(new BasicNameValuePair("name", "geotable80"));
    params.add(new BasicNameValuePair("is_published", "1"));
    params.add(new BasicNameValuePair("sn", sn));
    HttpEntity formEntity = new UrlEncodedFormEntity(params);
    post.setEntity(formEntity);
    HttpResponse response = client.execute(post);
    InputStream is = response.getEntity().getContent();
    String result = inStream2String(is);
    // 打印响应内容
    System.out.println(result);
  }

  // 对Map内所有value作utf8编码，拼接返回结果
  public String toQueryString(Map<?, ?> data) throws UnsupportedEncodingException {
    StringBuffer queryString = new StringBuffer();
    for (Entry<?, ?> pair : data.entrySet()) {
      queryString.append(pair.getKey() + "=");
      queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8") + "&");
    }
    if (queryString.length() > 0) {
      queryString.deleteCharAt(queryString.length() - 1);
    }
    return queryString.toString();
  }

  // 来自stackoverflow的MD5计算方法，调用了MessageDigest库函数，并把byte数组结果转换成16进制
  public String MD5(String md5) {
    try {
      java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
      byte[] array = md.digest(md5.getBytes());
      StringBuffer sb = new StringBuffer();
      for (int i = 0; i < array.length; ++i) {
        sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1, 3));
      }
      return sb.toString();
    } catch (java.security.NoSuchAlgorithmException e) {
    }
    return null;
  }

  // 将输入流转换成字符串
  private static String inStream2String(InputStream is) throws Exception {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    byte[] buf = new byte[1024];
    int len = -1;
    while ((len = is.read(buf)) != -1) {
      baos.write(buf, 0, len);
    }
    return new String(baos.toByteArray(), "UTF-8");
  }
}